using UnityEngine;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.IO;
using System.Collections;
using Frankfort.Threading.Internal;

public enum BundleType
{
	normal,
    shader,
	sprite_sheet,
	prefab,
    scene,
	code,
}

class BundleNotFoundException: System.Exception
{
	public BundleNotFoundException(string msg):base(msg)
	{
	
	}
}

class LoadBundleException: System.Exception
{
	public LoadBundleException(string msg):base(msg)
	{
		
	}
}

//public class AssetToBundleMap
//{
//    public Dictionary<string, KeyValuePair<string, string>> shaderBundleMap = new Dictionary<string, KeyValuePair<string, string>>();
//    public Dictionary<string, string[]> sceneBundleMap = new Dictionary<string, string[]>();
//    public Dictionary<string, KeyValuePair<string, string[]>> assetBundleMap = new Dictionary<string, KeyValuePair<string, string[]>>();
//}

public class AssetToBundleMap
{
    public Dictionary<string, KeyValuePair<string, string>> shaderBundleMap = new Dictionary<string, KeyValuePair<string, string>>();
    public Dictionary<string, string> sceneBundleMap = new Dictionary<string, string>();
    public Dictionary<string, KeyValuePair<string, string>> assetBundleMap = new Dictionary<string, KeyValuePair<string, string>>();
}
    
public class Bundle
{
	public BundleType type;
    public bool split_by_scene;
    public LocalType local_type;
	public string[] dirs;
    public string[] excluded_assets;
    public bool is_dependenced;
    public int max_asset_num_per_bundle;
    public int max_size_per_bundle;

	public void Read(BinaryReader reader)
	{
		type = (BundleType)System.Enum.Parse(typeof(BundleType), reader.ReadString());
		int len = reader.ReadInt32();
		if(len > 0)
		{
			dirs = new string[len];
			for(int i = 0; i < len; i++)
			{
				dirs[i] = reader.ReadString();
			}
		}
	}

	public void Write(BinaryWriter writer)
	{
		writer.Write(type.ToString());
		int len = 0;
		if(dirs != null)
		{
			len = dirs.Length;
		}

		writer.Write(len);
		for(int i = 0; i < len; i++)
		{
			writer.Write(dirs[i]);
		}
	}
}

public class BundleLayer: Dictionary<string, Bundle>
{
	public void Read(BinaryReader reader)
	{
		int len = reader.ReadInt32();
		for(int i = 0; i < len; i++)
		{
			string name = reader.ReadString();
			Bundle bundle = new Bundle();
			bundle.Read(reader);
			this.Add(name, bundle);
		}

	}

	public void Write(BinaryWriter writer)
	{
		int len = this.Count;
		writer.Write(len);

		Dictionary<string, Bundle>.Enumerator enumerator = this.GetEnumerator();
		while(enumerator.MoveNext())
		{
			writer.Write(enumerator.Current.Key);
			enumerator.Current.Value.Write (writer);
		}
	}
}

public class BundleGroup
{
	public string[] groups;
	public string[] bundles;

	public void Read(BinaryReader reader)
	{
		int groupLen = reader.ReadInt32();
		groups = null;
		if(groupLen > 0)
		{
			groups = new string[groupLen];
		}
		for(int i = 0; i < groupLen; i++)
		{
			groups[i] = reader.ReadString();
		}

		int bundleLen = reader.ReadInt32();
		bundles = null;
		if(bundleLen > 0)
		{
			bundles = new string[bundleLen];
		}
		for(int i = 0; i < bundleLen; i++)
		{
			bundles[i] = reader.ReadString();
		}
	}
	
	public void Write(BinaryWriter writer)
	{
		int groupLen = 0;
		if(groups != null)
		{
			groupLen = groups.Length;
		}
		writer.Write(groupLen);
		for(int i = 0; i < groupLen; i++)
		{
			writer.Write(groups[i]);
		}

		int bundleLen = 0;
		if(bundles != null)
		{
			bundleLen = bundles.Length;
		}
		writer.Write(bundleLen);
		for(int i = 0; i < bundleLen; i++)
		{
			writer.Write(bundles[i]);
		}
	}
}

public class BundleConfig
{
	public BundleLayer bundles;
    public string[] local_files;
	public Dictionary<string, BundleGroup> groups;

	public static BundleConfig createByBytes(byte[] data)
	{
		try
		{
			BundleConfig newConfig = new BundleConfig();
			MemoryStream stream = new MemoryStream(data);
			BinaryReader reader = new BinaryReader(stream);
			newConfig = new BundleConfig();
			newConfig.Read(reader);
			return newConfig;
		}
		catch(System.Exception e)
		{
			Debug.LogException(e);
		}
		return null;
	}

	public byte[] toBytes()
	{
		try
		{
			MemoryStream stream = new MemoryStream();
			BinaryWriter writer = new BinaryWriter(stream);
			this.Write(writer);
			return stream.ToArray();
		}
		catch(System.Exception e)
		{
			Debug.LogException(e);
		}
		return null;
	}

	public void Read(BinaryReader reader)
	{
//		int len = reader.ReadInt32();
//		bundles = new BundleLayer[len];
//		for(int i = 0; i < len; i++)
//		{
//			BundleLayer layer = new BundleLayer();
//			layer.Read(reader);
//			bundles[i] = layer;
//		}

        BundleLayer layer = new BundleLayer();
        layer.Read(reader);
        bundles = layer;

		int groupLen = reader.ReadInt32();
		groups = new Dictionary<string, BundleGroup>();
		for(int i = 0; i < groupLen; i++)
		{
			string groupName = reader.ReadString();
			BundleGroup bundleGroup = new BundleGroup();
			bundleGroup.Read(reader);
			groups.Add(groupName, bundleGroup);
		}
	}

	public void Write(BinaryWriter writer)
	{
//		int len = bundles.Length;
//		writer.Write(len);
//		for(int i = 0; i < len; i++)
//		{
//			bundles[i].Write(writer);
//		}

        bundles.Write(writer);

        if (groups != null)
        {
            int groupLen = groups.Count;
            writer.Write(groupLen);
            Dictionary<string, BundleGroup>.Enumerator enumerator = groups.GetEnumerator();
            while (enumerator.MoveNext())
            {
                writer.Write(enumerator.Current.Key);
                enumerator.Current.Value.Write(writer);
            }
        }
	}

	public Bundle getBundle(string bundleName)
	{
//		for(int i = 0; i < bundles.Length; i++)
//		{
//			Dictionary<string, Bundle>.Enumerator enumerator = bundles[i].GetEnumerator();
//			while(enumerator.MoveNext())
//			{
//				if(enumerator.Current.Key == bundleName)
//				{
//					return enumerator.Current.Value;
//				}
//			}
//		}


        Dictionary<string, Bundle>.Enumerator enumerator = bundles.GetEnumerator();
        while(enumerator.MoveNext())
        {
            if(enumerator.Current.Key == bundleName)
            {
                return enumerator.Current.Value;
            }
        }

		return null;
	}

	public Dictionary<string, string> TextAssetToDirBundleMap()
	{
		Dictionary<string, string> dirBundleMap = new Dictionary<string, string>();
//		for(int i = 0; i < bundles.Length; i++)
//		{
//			BundleLayer layer = bundles[i];
//			Dictionary<string, Bundle>.Enumerator enumerator = layer.GetEnumerator();
//			while(enumerator.MoveNext())
//			{
//				string bundleName = enumerator.Current.Key;
//				string[] dirs = enumerator.Current.Value.dirs;
//
//				for(int k = 0; dirs != null && k < dirs.Length; k++)
//				{
//					try
//					{
//						dirBundleMap.Add(dirs[k], bundleName);
//					}
//					catch(System.Exception e)
//					{
//						Debug.LogException(e);
//						Debug.LogError("TextAssetToDirBundleMap: " + dirs[k] + " repeated");
//					}
//				}
//			}
//		}
		

        BundleLayer layer = bundles;
        Dictionary<string, Bundle>.Enumerator enumerator = layer.GetEnumerator();
        while(enumerator.MoveNext())
        {
            string bundleName = enumerator.Current.Key;
            string[] dirs = enumerator.Current.Value.dirs;

            for(int k = 0; dirs != null && k < dirs.Length; k++)
            {
                try
                {
                    dirBundleMap.Add(dirs[k], bundleName);
                }
                catch(System.Exception e)
                {
                    Debug.LogException(e);
                    Debug.LogError("TextAssetToDirBundleMap: " + dirs[k] + " repeated");
                }
            }
        }

		return dirBundleMap;
	}

	public HashSet<string> getAllBundles()
	{
		HashSet<string> set = new HashSet<string>();
//		for(int i = 0; i < bundles.Length; i++)
//		{
//			BundleLayer.Enumerator enumerator = bundles[i].GetEnumerator();
//			while(enumerator.MoveNext())
//			{
//				string bundleName = enumerator.Current.Key;
//				set.Add(bundleName);
//
//				Bundle bundle = getBundle(bundleName);
//			}
//		}


        BundleLayer.Enumerator enumerator = bundles.GetEnumerator();
        while(enumerator.MoveNext())
        {
            string bundleName = enumerator.Current.Key;
            set.Add(bundleName);

            Bundle bundle = getBundle(bundleName);
        }

		return set;
	}

	public bool getGroupBundles(string groupName, ref HashSet<string> set)
	{
		if(groupName == null)
		{
			return false;
		}

		if(groups == null)
		{
			return false;
		}

		BundleGroup group = null;
		if(!groups.TryGetValue(groupName, out group))
		{
			return false;
		}

		if(group.bundles != null)
		{
			for(int i = 0; i < group.bundles.Length; i++)
			{
				string bundleName = group.bundles[i];
				set.Add(bundleName);
			}
		}

		if(group.groups != null)
		{
			for(int i = 0; i< group.groups.Length; i++)
			{
				getGroupBundles(group.groups[i], ref set);
			}

			return true;
		}

		return false;
	}

	public HashSet<string> getLocalGroupBundles()
	{
		HashSet<string> bundles = new HashSet<string>();
		getGroupBundles("local", ref bundles);
		return bundles;
	}

	public BundleGroup getBundleGroup(string groupName)
	{
		if(groupName == null)
		{
			return null;
		}

		BundleGroup group = null;
		this.groups.TryGetValue(groupName, out group);
		return group;
	}
}

public class SceneBundleInfo
{
	public string[] sceneBundle;

	public void Write(BinaryWriter writer)
	{
		int len = sceneBundle.Length;
		writer.Write(len);
		for(int i = 0; i < len; i++)
		{
			writer.Write(sceneBundle[i]);
		}
	}
	
	public void Write(StringWriter writer)
	{
		
	}
	
	public void Read(BinaryReader reader)
	{
		int len = reader.ReadInt32();
		sceneBundle = new string[len];
		for(int i = 0; i < len; i++)
		{
			sceneBundle[i] = reader.ReadString();
		}
	}

	public static SceneBundleInfo CreateByBytes(byte[] bytes)
	{
		if(bytes == null || bytes.Length <= 0)
		{
			return null;
		}
		MemoryStream stream = new MemoryStream(bytes);
		BinaryReader reader = new BinaryReader(stream);
		SceneBundleInfo prepareBundleNames = new SceneBundleInfo();
		prepareBundleNames.Read(reader);
		return prepareBundleNames;
	}
}

public struct DependienceGroup
{
	public byte[] bundleIndexs;
}

public class DependienceInfo
{
	public string[] bundles;
	public DependienceGroup[] groups;
	public Dictionary<string, short> pathGroupMap;

	public void Write(BinaryWriter writer)
	{
		int bundleLen = bundles.Length;
		writer.Write(bundleLen);
		for(int i = 0; i < bundles.Length; i++)
		{
			writer.Write(bundles[i]);
		}

		int groupLen = groups.Length;
		writer.Write(groupLen);
		for(int i = 0; i < groups.Length; i++)
		{
			int indexLen = groups[i].bundleIndexs.Length;
			writer.Write(indexLen);
			writer.Write(groups[i].bundleIndexs);
		}

		int mapLen = pathGroupMap.Count;
		writer.Write(mapLen);
		Dictionary<string, short>.Enumerator enumerator = pathGroupMap.GetEnumerator();
		while(enumerator.MoveNext())
		{
			string path = enumerator.Current.Key;
			short groupIndex = enumerator.Current.Value;
			writer.Write(path);
			writer.Write(groupIndex);
		}
	}
	
	public void Write(StringWriter writer)
	{
		
	}
	
	public void Read(BinaryReader reader)
	{
		int bundleLen = reader.ReadInt32();
		bundles = new string[bundleLen];
		for(int i = 0; i < bundles.Length; i++)
		{
			bundles[i] = reader.ReadString();
		}

		int groupLen = reader.ReadInt32();
		groups = new DependienceGroup[groupLen];
		for(int i = 0; i < groupLen; i++)
		{
			int indexLen = reader.ReadInt32();
			groups[i].bundleIndexs = reader.ReadBytes(indexLen);
		}

		pathGroupMap = new Dictionary<string, short>();
		int mapLen = reader.ReadInt32();
		for(int i = 0; i < mapLen; i++)
		{
			string path = reader.ReadString();
			short index = reader.ReadInt16();
			pathGroupMap.Add(path, index);
		}
	}

	public static DependienceInfo CreateByBytes(byte[] bytes)
	{
		if(bytes == null || bytes.Length <= 0)
		{
			return null;
		}

		DependienceInfo dependiencesMap = new DependienceInfo();
		MemoryStream stream = new MemoryStream(bytes);
		BinaryReader reader = new BinaryReader(stream);
		dependiencesMap.Read(reader);
		return dependiencesMap;
	}
}

// public class LoadedBundleInfo
// {
// 	public Dictionary<string, DependienceInfo> dependenciesMap = new Dictionary<string, DependienceInfo>();
// 	public SceneBundleInfo sceneBundles;
// 	public AssetBundle bundle;
// 	public float usedTime;
// 	public LinkedListNode<LoadedBundleInfo> listNode;

// 	public void unload(bool isAll)
// 	{
// 		if(bundle == null)
// 		{
// 			return;
// 		}

// 		bundle.Unload(isAll);
// 		bundle = null;
// 		listNode = null;
// 		usedTime = 0;
// 	}
// }

public class BundleManager: Singleton<BundleManager>
{
	public const float unloadMaxTime = 30;
    public const string bundleConfigName = "bundle_config.txt";
	public const string configName = "config";
	public const string dependenceName = "dependence";
	public const string sceneBundleDependenceSuffix = "_dependence";
	public const string sceneConfigBundleSuffix = "_config";
//	private const bool enableUnloadBundle = true;
	
//	private BundleConfig config;
//	private Dictionary<string, string> dirBundleMap;
//	private Dictionary<string, LoadedBundleInfo> assetBundleMap = new Dictionary<string, LoadedBundleInfo>();
//	private LinkedList<LoadedBundleInfo> latestUsedBundleList = new LinkedList<LoadedBundleInfo>();
//	private bool isEnable = true;
//	private bool isShowException = true;
//
//	public bool enable
//	{
//		get
//		{
//			return isEnable;
//		}
//		set
//		{
//			isEnable = value;
//			if(!isEnable)
//			{
//				UnloadAll(true);
//			}
//		}
//	}
//
//	public bool showException
//	{
//		get
//		{
//			return isShowException;
//		}
//		set
//		{
//			isShowException = value;
//		}
//	}
//
////	public void resetConfig()
////	{
////		config = null;
////	}
//
//	public void UnloadUnusedBundle()
//	{
//		if(enableUnloadBundle)
//		{
//			bool unloaded = false;
//			while(latestUsedBundleList.Count > 0)
//			{
//				LinkedListNode<LoadedBundleInfo> lastBundle = latestUsedBundleList.Last;
//				if(unloadMaxTime <= 0 || Time.time - lastBundle.Value.usedTime < unloadMaxTime)
//				{
//					break;
//				}
//				
//				LoadedBundleInfo tempBundle = unloadBundle(lastBundle.Value.bundle.name);
//				if(tempBundle == null)
//				{
//					Debug.LogError("unload bundle failed:" + lastBundle.Value.bundle.name);
//					break;
//				}
//				unloaded = true;
//			}
//			
//			if(unloaded)
//			{
//				Resources.UnloadUnusedAssets();
//				System.GC.Collect(0, System.GCCollectionMode.Optimized);
//			}
//		}
//	}
//
//	public static bool getBundleNameByPath(string resPath, string delPath, Dictionary<string, string> dirBundleMap, ref string dirName, ref string bundleName)
//	{
//		if(delPath != null && !resPath.Contains(delPath))
//		{
//			return false;
//		}
//
//		if(delPath != null)
//		{
//			resPath = resPath.Replace(delPath + "/", "");
//		}
//
//		Dictionary<string, string>.Enumerator enumerator = dirBundleMap.GetEnumerator();
//		while(enumerator.MoveNext())
//		{
//			bool canCompare = false;
//			if(resPath.Length == enumerator.Current.Key.Length)
//			{
//				canCompare = true;
//			}
//
//			if(resPath.Length > enumerator.Current.Key.Length)
//			{
//				if(resPath[enumerator.Current.Key.Length] == '/')
//				{
//					canCompare = true;
//				}
//			}
//
//			if(canCompare)
//			{
//				if(resPath.StartsWith(enumerator.Current.Key))
//				{
//					dirName = enumerator.Current.Key;
//					bundleName = enumerator.Current.Value;
//					return true;
//				}
//			}
//		}
//		return false;
//	}
//
//	public LoadedBundleInfo preLoad(string bundleName, string loadResPath, bool force = false)
//	{
//		if(!enable && !force)
//		{
//			return null;
//		}
//
//		if(!SwitchConfig.isEnableHotFix)
//		{
//			return null;
//		}
//
//		if(bundleName == null)
//		{
//			return null;
//		}
//
//		LoadedBundleInfo bundleInfo = null;
//		if(!assetBundleMap.TryGetValue(bundleName, out bundleInfo))
//		{
//			bundleInfo = new LoadedBundleInfo();
//			assetBundleMap.Add(bundleName, bundleInfo);
//		}
//
//		string inputPath = null;
//		if(bundleInfo.bundle == null)
//		{
////			if(SwitchConfig.isEnableLoadDownloadedBundle)
//			{
////				ExistBundleInfo existInfo = BundleVersionManager.instance.getExistBundleInfo(bundleName);
////				if(existInfo != null)
////				{
////					inputPath = System.IO.Path.Combine(BundleVersionManager.bundlePath, existInfo.fileName + BundleVersionManager.bundleExt2);
//////					if(!System.IO.File.Exists(inputPath))
//////					{
//////						inputPath = null;
//////					}
////				}
//			}
//
//			if(inputPath == null)
//			{
//				if(Application.platform == RuntimePlatform.IPhonePlayer || Application.isEditor)
//				{
//					inputPath = System.IO.Path.Combine(Application.streamingAssetsPath, bundleName + BundleVersionManager.bundleExt2);
//					if(!System.IO.File.Exists(inputPath))
//					{
//						inputPath = null;
//					}
//				}
//			}
//
//			if(Application.isPlaying)
//			{
//				try
//				{
//					if(inputPath != null)
//					{
//						bundleInfo.bundle = BundleManager.CreateFromFile(inputPath);
//
//						if(bundleInfo.bundle != null)
//						{
//							bundleInfo.bundle.name = bundleName;
//						}
//					}
//				}
//				catch(System.Exception e)
//				{
//					Debug.LogError("load bundle failed: " + inputPath);
//					Debug.LogException(e);
//				}
//			}
//		}
//
//		if(bundleInfo != null && bundleInfo.bundle != null)
//		{
//			bundleInfo.usedTime = Time.time;
//			if(bundleInfo.listNode == null)
//			{
//				bundleInfo.listNode = latestUsedBundleList.AddFirst(bundleInfo);
//			}
//			else
//			{
//				latestUsedBundleList.Remove(bundleInfo.listNode);
//				latestUsedBundleList.AddFirst(bundleInfo.listNode);
//			}
//
////			unloadUnusedBundle();
//		}
//
//		if(bundleInfo.bundle == null)
//		{
//			if(!Application.isEditor && isShowException)
//			{
//				bool exist = inputPath != null && File.Exists(inputPath);
//				if(exist)
//				{
//					LoadBundleException e = new LoadBundleException("load bundle " + inputPath + " failed when load resource: " + loadResPath);
//					Debug.LogException(e);
//				}
//				else
//				{
//					BundleNotFoundException e = new BundleNotFoundException("bundle " + bundleName + " not found when load resource: " + loadResPath);
//					Debug.LogException(e);
//				}
//			}
//			return null;
//		}
//
//		return bundleInfo;
//	}
//
//	private LoadedBundleInfo getBundle(string bundleName)
//	{
//		if(bundleName == null)
//		{
//			return null;
//		}
//
//		LoadedBundleInfo bundle = null;
//		assetBundleMap.TryGetValue(bundleName, out bundle);
//		return bundle;
//	}
//
//    public void UnloadAll(bool forceUnloadAsset, bool unloadConfig = true)
//	{
//		if(enableUnloadBundle)
//		{
//			latestUsedBundleList.Clear();
//			Dictionary<string, LoadedBundleInfo>.Enumerator enumerator = assetBundleMap.GetEnumerator();
//			while(enumerator.MoveNext())
//			{
//                enumerator.Current.Value.unload(forceUnloadAsset);
//			}
//			assetBundleMap.Clear();
//
//            if (unloadConfig)
//            {
//                config = null;
//                dirBundleMap = null;
//            }
//
//			Resources.UnloadUnusedAssets();
//			System.GC.Collect(0, System.GCCollectionMode.Forced);
//		}
//	}
//	
//	private LoadedBundleInfo unloadBundle(string bundleName, bool isAll = false)
//	{
//		if(bundleName == null)
//		{
//			return null;
//		}
//		
//		LoadedBundleInfo bundle = null;
//		assetBundleMap.TryGetValue(bundleName, out bundle);
//		if(bundle != null)
//		{
//			if(enableUnloadBundle)
//			{
//				assetBundleMap.Remove(bundleName);
//				if(bundle.listNode != null)
//				{
//					latestUsedBundleList.Remove(bundle.listNode);
//				}
//				bundle.unload(isAll);
//			}
//		}
//		return bundle;
//	}
//
//	public Sprite LoadSprite(string asset)
//	{
//		return Load<Sprite>(asset);
//	}
//
//	public AssetBundleRequest LoadSpriteAsync(string asset)
//	{
//		return LoadAsync<Sprite>(asset);
//	}
//
//    public Font LoadFont(string asset)
//    {
//        return Load<Font>(asset);
//    }
//
//	LoadedBundleInfo prepareForLoad(ref string asset)
//	{
//		if(!initDirBundleMap())
//		{
//			return null;
//		}
//		
//		string dirName = null;
//		string bundleName = null;
//		string realAsset = asset;
//		if(!getBundleNameByPath(realAsset, null, dirBundleMap, ref dirName, ref bundleName))
//		{
//			return null;
//		}
//
//		LoadedBundleInfo bundle2 = preLoad(bundleName, asset);
//		asset = asset.Replace('/', ResourcesEx.dirSymbol);
//		return bundle2;
//	}
//
//    public Object Load(string asset, System.Type t)
//    {
//        return null;
//    }
//
//	public T Load<T>(string asset) where T : class
//	{
//		LoadedBundleInfo bundle2 = prepareForLoad(ref asset);
//		
//		T Obj = null;
//		if(bundle2 != null)
//		{
//			Obj = LoadAsset<T>(bundle2.bundle, asset);
//		}
//		return Obj;
//	}
//
//    public AssetBundleRequest LoadAsync(string asset, System.Type t)
//    {
////        LoadedBundleInfo bundle2 = prepareForLoad(asset);
////        if(bundle2 == null)
////        {
////            return null;
////        }
////
////        AssetBundleRequest request = LoadAssetAsync<T>(bundle2.bundle, asset, t);
////        return request;
//        return null;
//    }
//
//	public AssetBundleRequest LoadAsync<T>(string asset) where T : class
//	{
//		LoadedBundleInfo bundle2 = prepareForLoad(ref asset);
//		if(bundle2 == null)
//		{
//			return null;
//		}
//
//		AssetBundleRequest request = LoadAssetAsync<T>(bundle2.bundle, asset);
//		return request;
//	}
//
//	public bool initDirBundleMap(bool focus = false)
//	{
//		if(dirBundleMap == null)
//		{
//			string configPath = EvonyPlatform.getPlatform().ToString() + ResourcesEx.dirSymbol + configName;
//
//			bool temp = this.showException;
//			this.showException = false;
//			LoadedBundleInfo bundle = preLoad(configName, configPath, focus);
//			this.showException = temp;
//			if(bundle == null)
//			{
//				return false;
//			}
//
//			TextAsset textAsset = LoadAsset<TextAsset>(bundle.bundle, configPath);
//			if(textAsset == null)
//			{
//				return false;
//			}
//
//			try
//			{
//				config = BundleConfig.createByBytes(textAsset.bytes);
////				MemoryStream stream = new MemoryStream();
////				BinaryReader reader = new BinaryReader(stream);
////				config = new BundleConfig();
////				config.Read(reader);
//
//				dirBundleMap = config.TextAssetToDirBundleMap();
//			}
//			catch(System.Exception e)
//			{
//				Debug.LogException(e);
//				Debug.LogError("BundleManager: DeserializeObject failed");
//			}
//		}
//
//		return dirBundleMap != null;
//	}
//
//	public override string ToString()
//	{
//		string str = "";
//		if(assetBundleMap != null)
//		{
//			Dictionary<string, LoadedBundleInfo>.Enumerator enumerator = assetBundleMap.GetEnumerator();
//			while(enumerator.MoveNext())
//			{
//				if(enumerator.Current.Value != null && enumerator.Current.Value.bundle != null)
//				{
//					str += enumerator.Current.Key + "\n";
//				}
//			}
//		}
//		return str;
//	}
//
//	public HashSet<string> getAllBundleNames()
//	{
//		HashSet<string> bundles = new HashSet<string>();
//		foreach(string bundleName in dirBundleMap.Values)
//		{
//			bundles.Add(bundleName);
//		}
//		return bundles;
//	}
//
//	public BundleConfig getConfig(bool focus = false)
//	{
//		initDirBundleMap(focus);
//		return config;
//	}
//
//	public Object LoadPrefab(string asset)
//	{
//		return LoadWithDependencies<Object>(asset, ".prefab");
//	}
//
//	public AssetBundleRequest LoadPrefabAsync(string asset)
//	{
//		return LoadWithDependenciesAsync<GameObject>(asset, ".prefab");
//	}
//
//	public RuntimeAnimatorController LoadAnimatorController(string asset)
//	{
//		return LoadWithDependencies<RuntimeAnimatorController>(asset, ".controller");
//	}
//
//	private LoadedBundleInfo prepareDependiceBundle (ref string asset, string ext)
//	{
//		if (!initDirBundleMap ())
//		{
//			return null;
//		}
//
//		string dirName = null;
//		string bundleName = null;
//		getBundleNameByPath (asset, null, dirBundleMap, ref dirName, ref bundleName);
//		LoadedBundleInfo bundle2 = preLoad (bundleName, asset);
//		if (bundle2 == null)
//		{
//			return null;
//		}
//
//		DependienceInfo dependiencesMap = null;
//		if (!bundle2.dependenciesMap.TryGetValue (dirName, out dependiencesMap))
//		{
//			dependiencesMap = bundle2.bundle.getDependenceInfo (dirName);
//			bundle2.dependenciesMap.Add (dirName, dependiencesMap);
//		}
//
//		if (dependiencesMap != null)
//		{
//			try
//			{
//				string prefabKey = asset.Remove (0, dirName.Length + 1);
//				prefabKey += ext;
//				short groupIndex = 0;
//				if (dependiencesMap.pathGroupMap.TryGetValue (prefabKey, out groupIndex))
//				{
//					byte[] bundleIndexs = dependiencesMap.groups [groupIndex].bundleIndexs;
//					for (int i = 0; i < bundleIndexs.Length; i++)
//					{
//						LoadedBundleInfo prepareBundle = preLoad (dependiencesMap.bundles [bundleIndexs [i]], asset);
//						if (prepareBundle == null)
//						{
//							//						return null;
//						}
//					}
//				}
//			}
//			catch (System.Exception e)
//			{
//				if (Debug.enableLog) Debug.LogException (e);
//				if (Debug.enableLog) Debug.LogError ("BundleManager: preload dependence bundle failed");
//			}
//		}
//
//		asset = asset.Replace ('/', ResourcesEx.dirSymbol);
//		return bundle2;
//	}
//
//	public Material LoadMaterial(string asset)
//	{
//		return LoadWithDependencies<Material>(asset, ".mat");
//	}
//
//	public static AssetBundle CreateFromFile(string inputPath)
//	{
//		#if UNITY_5
//		return AssetBundle.LoadFromFile(inputPath);
//		#else
//		return AssetBundle.CreateFromFile(inputPath);
//		#endif
//	}
//
//	public static T LoadAsset<T>(AssetBundle bundle, string asset) where T : class
//	{
//		T Obj = null;
//		#if UNITY_5
//		Obj = bundle.LoadAsset(asset, typeof(T)) as T;
//		#else
//		Obj = bundle.Load(asset, typeof(T)) as T;
//		#endif
//		return Obj;
//	}
//
//	public static Object[] LoadAll(AssetBundle bundle)
//	{
//		#if UNITY_5
//		return bundle.LoadAllAssets();
//		#else
//		return bundle.LoadAll();
//		#endif
//	}
//
//	public static Object[] LoadAll(AssetBundle bundle, System.Type t)
//	{
//		#if UNITY_5
//		return bundle.LoadAllAssets(t);
//		#else
//		return bundle.LoadAll(t);
//		#endif
//	}
//
//	public static AssetBundleRequest LoadAssetAsync<T>(AssetBundle bundle, string asset) where T : class
//	{
//		AssetBundleRequest Obj = null;
//		#if UNITY_5
//		Obj = bundle.LoadAssetAsync(asset, typeof(T));
//		#else
//		Obj = bundle.LoadAsync(asset, typeof(T));
//		#endif
//		return Obj;
//	}
//
//	public T LoadWithDependencies<T>(string asset, string ext) where T : class
//	{
//		LoadedBundleInfo bundle2 = prepareDependiceBundle (ref asset, ext);
//
//		if(bundle2 == null)
//		{
//			return null;	
//		}
//
//		return LoadAsset<T>(bundle2.bundle, asset);
//	}
//	
//	public AssetBundleRequest LoadWithDependenciesAsync<T>(string asset, string ext) where T : class
//	{
//		LoadedBundleInfo bundle2 = prepareDependiceBundle (ref asset, ext);
//		if(bundle2 == null)
//		{
//			return null;
//		}
//
//		AssetBundleRequest request = null;
//		request = LoadAssetAsync<T>(bundle2.bundle, asset);
//		return request;
//	}
//
//	public bool prepareForLevel(string levelName)
//	{
//		if(!initDirBundleMap())
//		{
//			return false;
//		}
//
//		LoadedBundleInfo levelBundle = getBundle(levelName);
//		SceneBundleInfo prepareBundleNames = null;
//		if(levelBundle != null)
//		{
//			prepareBundleNames = levelBundle.sceneBundles;
//		}
//
//		if(prepareBundleNames == null)
//		{
//			string configBundleName = levelName + sceneConfigBundleSuffix;
//
//			bool temp = isShowException;
//			isShowException = false;
//			LoadedBundleInfo configBundle = preLoad(configBundleName, levelName);
//			isShowException = temp;
//
//			if(configBundle == null)
//			{
//				return false;
//			}
//
//			prepareBundleNames = configBundle.bundle.getSceneBundleInfo(levelName);
//			unloadBundle(configBundleName, true);
//			configBundle = null;
//
//			if(prepareBundleNames == null)
//			{
//				return false;
//			}
//		}
//
//		if(prepareBundleNames != null)
//		{
//			for(int i = 0; i < prepareBundleNames.sceneBundle.Length; i++)
//			{
//				LoadedBundleInfo prepareBundle = this.preLoad(prepareBundleNames.sceneBundle[i], levelName);
//				if(prepareBundle == null)
//				{
//					
//				}
//			}
//		}
//
//		LoadedBundleInfo sceneBundle = preLoad(levelName, levelName);
//		sceneBundle.sceneBundles = prepareBundleNames;
//		return true;
//	}
}

public class NewBundleManager: Singleton<NewBundleManager>
{
    public static readonly string assetToBundleConfigName = "asset_to_bundle";
    public static readonly string assetToBundleConfigPath = "Assets/asset_bundle/" + assetToBundleConfigName + ".txt";
    public static readonly string configBundleName = "config";

    BundleVersionConfig config;
    AssetToBundleMap assetToBundleMap;
    Dictionary<string, AssetBundle> bundleMap = new Dictionary<string, AssetBundle>();
    AssetBundleManifest manifest;
    Dictionary<string, IEnumerator> createBundleIEnumeratorMap = new Dictionary<string, IEnumerator>();

    public override string ToString()
    {
        string log = "";
        log += "count: " + bundleMap.Count + "\n";
        foreach (var entry in bundleMap)
        {
            log += entry.Key + "\n";
        }

        return log;
    }

    public AssetBundle GetAssetBundle(string bundleName)
    {
        if(this.config == null)
        {
            return null;
        }

        string hashConfigBundleName = configBundleName;
        if(this.config.bundle_name_encoded)
        {
            hashConfigBundleName = ConvertToHashName(configBundleName);
        }

        AssetBundle ab = null;
        bundleMap.TryGetValue(hashConfigBundleName, out ab);
        return ab;
    }

    public void LoadAll()
    {
        if (config == null)
        {
            return;
        }

        foreach (var entry in config.bundles)
        {
            LoadAssetBundle(entry.Key);
        }
    }

    public void UnloadAll(bool forceUnloadAssets)
    {
        // Debug.LogError("unload all asset bundle");
		Dictionary<string, AssetBundle>.Enumerator e = bundleMap.GetEnumerator();
        while (e.MoveNext())
        {
            e.Current.Value.Unload(forceUnloadAssets);
        }
        bundleMap.Clear ();
    }

    public static string ConvertToHashName(string name)
    {
        return MD5Hash.GetMD5HashFromString(name);
    }

    public void SetVersionBundleConfig(BundleVersionConfig newConifg, MonoBehaviour behaviour, System.Action callback)
    {
        if (this.config != null && newConifg != null)
        {
            if (this.config.Equals(newConifg))
            {
                callback();
                return;
            }
        }

        ConsumeTime.Log("NewBundleManager.SetVersionBundleConfig_1", () =>
            {
            	UnloadAll(false);

                assetToBundleMap = null;
                manifest = null;

                createBundleIEnumeratorMap.Clear();
            });

        ConsumeTime.Log("NewBundleManager.SetVersionBundleConfig_2", () =>
            {
                this.config = newConifg;
                if (this.config != null)
                {
                    behaviour.StartCoroutine(ReadConfig(callback));
                }
                else
                {
                    callback();
                }
            });
    }

    IEnumerator ReadConfig(System.Action callback)
    {
        IEnumerator e = LoadAssetBundleAsync("manifest", 0);
        while (e.MoveNext())
        {
            yield return null;
        }
        createBundleIEnumeratorMap.Remove("manifest");

        AssetBundle manifestBundle = bundleMap["manifest"];
            
        {
            AssetBundleRequest request = manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
            while(!request.isDone)
            {
                yield return null;
            }
            manifest = request.asset as AssetBundleManifest;
        }

        string hashConfigBundleName = configBundleName;
        if(this.config.bundle_name_encoded)
        {
            hashConfigBundleName = ConvertToHashName(configBundleName);
        }
        IEnumerator e2 = LoadAssetBundleAsync(hashConfigBundleName, 0);
        while (e2.MoveNext())
        {
            yield return null;
        }
        createBundleIEnumeratorMap.Remove(hashConfigBundleName);

        AssetBundle bundle = bundleMap[hashConfigBundleName];
        if (bundle == null)
        {
            throw new System.Exception("config bundle not found");
        }

        {
            AssetBundleRequest request = bundle.LoadAssetAsync<TextAsset>(assetToBundleConfigPath);
            while(!request.isDone)
            {
                yield return null;
            }
            TextAsset asset = request.asset as TextAsset;
            string str = asset.text;

            SingleThreadStarter.StartSingleThread(() =>
                {
                    assetToBundleMap = JsonConvert.DeserializeObject<AssetToBundleMap>(str);

                    MainThreadDispatcher.DispatchToMainThread(() =>
                        {
                            callback();
                        });
                });
        }
    }


    //            Dictionary<string, HashSet<string>> bundleDependMap = new Dictionary<string, HashSet<string>>();
    //            string[] bundleNames = manifest.GetAllAssetBundles();
    //            for (int i = 0; i < bundleNames.Length; i++)
    //            {
    //                string[] directDependedBundleNames = manifest.GetDirectDependencies(bundleNames[i]);
    //                bundleDependMap.Add(bundleNames[i], new HashSet<string>(directDependedBundleNames));
    //            }
    //
    //            Queue<string> q = new Queue<string>();
    //            for (int i = 0; i < bundleNames.Length; i++)
    //            {
    //                bool found = false;
    //                foreach(var entry in bundleDependMap)
    //                {
    //                    if(entry.Value.Contains(bundleNames[i]))
    //                    {
    //                        found = true;
    //                        break;
    //                    }
    //                }
    //
    //                if(!found)
    //                {
    //                    q.Enqueue(bundleNames[i]);
    //                }
    //            }
    //
    //            Dictionary<string, int> bundleDepthMap = new Dictionary<string, int>();
    //            while(q.Count > 0)
    //            {
    //                string node = q.Dequeue();
    //                SearchDepth(node, bundleDependMap, bundleDepthMap);
    //            }
    //
    //            System.Array.Sort(bundleNames, (a, b) =>
    //                {
    //                    return bundleDepthMap[b] - bundleDepthMap[a];
    //                });
    //
    //            string log = "LoadAssetBundle: ";
    //            for (int i = 0; i < bundleNames.Length; i++)
    //            {
    //                log += "\n" + bundleNames[i];
    //                LoadAssetBundle(bundleNames[i]);
    //            }
    //
    //            Debug.LogError(log);

    void SearchDepth(string bundleName, Dictionary<string, HashSet<string>>bundleDependMap, Dictionary<string, int> bundleDepthMap, int depth = 0)
    {
        int tempDepth = 0;
        if (bundleDepthMap.TryGetValue(bundleName, out tempDepth))
        {
            if (depth > tempDepth)
            {
                bundleDepthMap[bundleName] = depth;
            }
        }
        else
        {
            bundleDepthMap.Add(bundleName, depth);
        }

        HashSet<string> dependedBundleNames = null;
        if (bundleDependMap.TryGetValue(bundleName, out dependedBundleNames))
        {
            foreach (var b in dependedBundleNames)
            {
                SearchDepth(b, bundleDependMap, bundleDepthMap, depth + 1);
            }
        }
    }

    AssetBundle LoadAssetBundle(string bundleName, int depth = 0)
    {
        if (string.IsNullOrEmpty(bundleName))
        {
            return null;
        }

        AssetBundle bundle = null;
        if (bundleMap.TryGetValue(bundleName, out bundle))
        {
            return bundle;
        }

//        Debug.LogError("test_depth: " + depth + "  " + bundleName);
        if (manifest != null)
        {
            string[] directDependencies = manifest.GetDirectDependencies(bundleName);
            for (int i = 0; i < directDependencies.Length; i++)
            {
                LoadAssetBundle(directDependencies[i], depth + 1);
            }
        }

//        if (createBundleIEnumeratorMap.ContainsKey(bundleName))
//        {
//            Debug.LogError("repeat: " + bundleName);
//        }

        string bundleFilePath = BundleVersionManager.instance.GetBundleFilePath(bundleName);
		if (string.IsNullOrEmpty (bundleFilePath))
		{
            Debug.LogWarning("asset bundle file don't exist:" + bundleName);
            return null;
//			throw new System.Exception("asset bundle file don't exist:" + bundleName);
		}

        bundle = AssetBundle.LoadFromFile(bundleFilePath);
        if (bundle == null)
        {
			throw new System.Exception("asset bundle file not found: " + bundleFilePath + "    bundleName:" + bundleName);
        }

        bundleMap.Add(bundleName, bundle);
        return bundle;
    }

//    Dictionary<string, AssetBundleCreateRequest> createBundleRequestMap = new Dictionary<string, AssetBundleCreateRequest>();

//    AssetBundleCreateRequest CreateLoadAssetBundleRequest(string bundleName)
//    {
//        AssetBundleCreateRequest request = null;
//        if (!createBundleRequestMap.TryGetValue(bundleName, out request))
//        {
//            string bundleFilePath = BundleVersionManager.instance.GetBundleFilePath(bundleName);
//            if (string.IsNullOrEmpty (bundleFilePath))
//            {
//                throw new System.Exception("asset bundle file not found: " + bundleFilePath + "    bundleName:" + bundleName);
//            }
//
//            request = AssetBundle.LoadFromFileAsync(bundleFilePath);
//            createBundleRequestMap.Add(bundleName, request);
//        }
//
//        return request;
//    }
//
//    IEnumerator RealLoadAssetBundleAsync(string bundleName)
//    {
//        AssetBundleCreateRequest request = CreateLoadAssetBundleRequest(bundleName);
//        while (!request.isDone && !bundleMap.ContainsKey(bundleName))
//        {
//            yield return null;
//        }
//
//        createBundleRequestMap.Remove(bundleName);
//
//        if (!bundleMap.ContainsKey(bundleName))
//        {
//            if (request.assetBundle == null)
//            {
//                throw new System.Exception("load asset bundle async failed:" + bundleName);
//            }
//            bundleMap.Add(bundleName, request.assetBundle);
//        }
//    }

    IEnumerator LoadAssetBundleAsync(string bundleName, int priority)
    {
        IEnumerator e = null;
        if (!createBundleIEnumeratorMap.TryGetValue(bundleName, out e))
        {
            e = LoadAssetBundleAsync2(bundleName, priority);
            createBundleIEnumeratorMap.Add(bundleName, e);
        }
        return e;
    }

    IEnumerator LoadAssetBundleAsync2(string bundleName, int priority)
    {
        if (!string.IsNullOrEmpty(bundleName))
        {
            AssetBundle bundle = null;
            if (bundleMap.TryGetValue(bundleName, out bundle))
            {

            }
            else
            {
                if (manifest != null)
                {
                    string[] directDependencies = manifest.GetDirectDependencies(bundleName);
                    if (directDependencies.Length > 0)
                    {
                        IEnumerator[] es = new IEnumerator[directDependencies.Length];
                        for (int i = 0; i < directDependencies.Length; i++)
                        {
                            string d = directDependencies[i];
                            IEnumerator e = LoadAssetBundleAsync(d, priority);
                            es[i] = e;
                        }

                        while (true)
                        {
                            bool finish = true;
                            for (int i = 0; i < es.Length; i++)
                            {
                                if (es[i].MoveNext())
                                {
                                    finish = false;
                                }
                            }

                            if (finish)
                            {
                                for (int i = 0; i < directDependencies.Length; i++)
                                {
                                    string d = directDependencies[i];
                                    this.createBundleIEnumeratorMap.Remove(d);
                                }
                                break;
                            }

                            yield return null;
                        }
                    }
                }

                {
                    if (!bundleMap.ContainsKey(bundleName))
                    {
                        string bundleFilePath = BundleVersionManager.instance.GetBundleFilePath(bundleName);
                        if (string.IsNullOrEmpty (bundleFilePath))
                        {
                            throw new System.Exception("asset bundle file not found: " + bundleFilePath + "    bundleName:" + bundleName);
                        }

                        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundleFilePath);
                        request.priority = priority;

                        while (!request.isDone && !bundleMap.ContainsKey(bundleName))
                        {
                            yield return null;
                        }

                        if (!bundleMap.ContainsKey(bundleName))
                        {
                            if (request.assetBundle == null)
                            {
                                throw new System.Exception("load asset bundle async failed:" + bundleName);
                            }
                            bundleMap.Add(bundleName, request.assetBundle);
                        }
                    }
                }
            }
        }
    }
    public Shader LoadShader(string shaderName)
    {
        if (assetToBundleMap == null)
        {
            return null;
        }

        KeyValuePair<string, string> fileBundlePair = new KeyValuePair<string, string>();
        if (assetToBundleMap.shaderBundleMap.TryGetValue(shaderName, out fileBundlePair))
        {
//            AssetBundle mainBundle = null;
//            mainBundle = LoadAssetBundle(fileBundlePair.Value);
//            string[] dependedBundles = manifest.GetAllDependencies(fileBundlePair.Value);
//            for (int i = 0; i < dependedBundles.Length; i++)
//            {
//                LoadAssetBundle(dependedBundles[i]);
//            }
//            return mainBundle.LoadAsset<Shader>(fileBundlePair.Key);


            AssetBundle mainBundle = LoadAssetBundle(fileBundlePair.Value);
            if (mainBundle != null)
            {
                return mainBundle.LoadAsset<Shader>(fileBundlePair.Key);
            }
        }

        return null;
    }

    public bool PrepareForLoadScene(string sceneName)
    {
        if (assetToBundleMap == null)
        {
            return false;
        }

//        string[] bundleNames = null;
//        if (assetToBundleMap.sceneBundleMap.TryGetValue(sceneName, out bundleNames))
//        {
////            string[] dependedBundles = manifest.GetAllDependencies(bundleNames[0]);
////            for (int i = 0; i < dependedBundles.Length; i++)
////            {
////                LoadAssetBundle(dependedBundles[i]);
////            }
//
////            for (int i = 1; i < bundleNames.Length; i++)
////            {
////                LoadAssetBundle(bundleNames[i]);
////            }
//            LoadAssetBundle(bundleNames[0]);
//
//            return true;
//        }

        string bundleNames = null;
        if (assetToBundleMap.sceneBundleMap.TryGetValue(sceneName, out bundleNames))
        {
            LoadAssetBundle(bundleNames);
            return true;
        }

        return false;
    }

    public AsyncOperationEx PrepareForLoadSceneAsync(string sceneName, int priority)
    {
        if (assetToBundleMap == null)
        {
            return null;
        }

        string bundleNames = null;
        if (assetToBundleMap.sceneBundleMap.TryGetValue(sceneName, out bundleNames))
        {
            LoadAssetAsyncOperation operation = new LoadAssetAsyncOperation(bundleNames, null, null, priority);
            return operation;
        }

        return null;
    }

    public T LoadAsset<T>(string assetPath) where T: UnityEngine.Object
    {
        return LoadAsset(assetPath, typeof(T)) as T;
    }

    public Object LoadAsset(string assetPath)
    {
        return LoadAsset(assetPath, null);
    }

    public Object LoadAsset(string assetPath, System.Type t)
    {
        if (assetToBundleMap == null)
        {
            return null;
        }

//        KeyValuePair<string, string[]> info = new KeyValuePair<string, string[]>();
//        if (assetToBundleMap.assetBundleMap.TryGetValue(assetPath, out info))
//        {
////            AssetBundle mainBundle = null;
////            mainBundle = LoadAssetBundle(bundleNames[0]);
////            string[] dependedBundles = manifest.GetAllDependencies(bundleNames[0]);
////            for (int i = 0; i < dependedBundles.Length; i++)
////            {
////                LoadAssetBundle(dependedBundles[i]);
////            }
//
////            for (int i = 1; i < bundleNames.Length; i++)
////            {
////                LoadAssetBundle(bundleNames[i]);
////            }
//
//            AssetBundle mainBundle = LoadAssetBundle(info.Value[0]);
//            if (mainBundle != null)
//            {
////                string fileName = Path.GetFileName(assetPath);
////                return Load(mainBundle, fileName, t);
//                string filePath = ResourcesEx.BundleResDir + "/" + assetPath + info.Key;
//                return Load(mainBundle, filePath, t);
//            }
//        }

        KeyValuePair<string, string> info = new KeyValuePair<string, string>();
        if (assetToBundleMap.assetBundleMap.TryGetValue(assetPath, out info))
        {
            AssetBundle mainBundle = LoadAssetBundle(info.Value);
            if (mainBundle != null)
            {
                string filePath = info.Key;
                return Load(mainBundle, filePath, t);
            }
        }

        return null;
    }

    Object Load(AssetBundle bundle, string assetName, System.Type t)
    {
        if (bundle == null || string.IsNullOrEmpty(assetName))
        {
            return null;
        }

        if (t == null)
        {
            return bundle.LoadAsset(assetName);
        }
        else
        {
            return bundle.LoadAsset(assetName, t);
        }
    }

    public AsyncOperationEx LoadAssetAsync<T>(string assetPath, int priority) where T: UnityEngine.Object
    {
        return LoadAssetAsync(assetPath, typeof(T), priority);
    }

    public AsyncOperationEx LoadAssetAsync(string assetPath, int priority)
    {
        return LoadAssetAsync(assetPath, null, priority);
    }
        
    public class LoadAssetAsyncOperation: AsyncOperationEx
    {
        string bundleName;
        string filePath;
        System.Type t;
        AssetBundleRequest request;
        IEnumerator e;
        int priority;

        public LoadAssetAsyncOperation(string bundleName, string filePath, System.Type t, int priority)
        {
            this.bundleName = bundleName;
            this.filePath = filePath;
            this.t = t;
            this.priority = priority;

            e = Execute();
        }

        IEnumerator Execute()
        {
            IEnumerator loadBundleEnumerator = NewBundleManager.instance.LoadAssetBundleAsync(bundleName, this.priority);

            while(loadBundleEnumerator.MoveNext())
            {
                yield return null;
            }

            if(loadBundleEnumerator != null)
            {
                NewBundleManager.instance.createBundleIEnumeratorMap.Remove(bundleName);
            }
                
            if (!string.IsNullOrEmpty(filePath))
            {
                AssetBundle bundle = NewBundleManager.instance.bundleMap[bundleName];
                request = NewBundleManager.instance.LoadAsync(bundle, filePath, t);
                request.priority = this.priority;
                while (!request.isDone)
                {
                    yield return null;
                }
            }
        }

        public override Object asset
        {
            get
            {
                if (request != null)
                {
                    return request.asset;
                }
                return null;
            }
        }

        public override bool isDone
        {
            get
            {
                return !e.MoveNext();
            }
        }

        public override bool allowSceneActivation
        {
            get
            {
                return false;
            }

            set
            {
                
            }
        }

        public override float progress
        {
            get
            {
                if (request != null)
                {
                    return request.progress;
                }
                return 0;
            }
        }
    }

    public AsyncOperationEx LoadAssetAsync(string assetPath, System.Type t, int priority)
    {
        if (assetToBundleMap == null)
        {
            return null;
        }
        
        KeyValuePair<string, string> info = new KeyValuePair<string, string>();
        if (assetToBundleMap.assetBundleMap.TryGetValue(assetPath, out info))
        {
            LoadAssetAsyncOperation operation = new LoadAssetAsyncOperation(info.Value, info.Key, t, priority);
            return operation;
        }
        else
        {
            return null;
        }
    }

    AssetBundleRequest LoadAsync(AssetBundle bundle, string assetName, System.Type t)
    {
        if (bundle == null || string.IsNullOrEmpty(assetName))
        {
            return null;
        }

        if (t == null)
        {
            return bundle.LoadAssetAsync(assetName);
        }
        else
        {
            return bundle.LoadAssetAsync(assetName, t);
        }
    }
}


public static class BundleExtension
{
//	public static DependienceInfo getDependenceInfo(this AssetBundle bundle, string dirName)
//	{
//		DependienceInfo dependiencesMap = null;
//		string replaceDirName = dirName.Replace('/', ResourcesEx.dirSymbol);
//		string prefabDirConfigName = replaceDirName + ResourcesEx.dirSymbol + BundleManager.dependenceName;
//		TextAsset prefabConfigAsset = BundleManager.LoadAsset<TextAsset>(bundle, prefabDirConfigName);
//
//		if(prefabConfigAsset != null)
//		{
//			try
//			{
//				dependiencesMap = DependienceInfo.CreateByBytes(prefabConfigAsset.bytes);
//			}
//			catch(System.Exception e)
//			{
//				Debug.LogException(e);
//				Debug.LogError("BundleManager: Deserialize DependienceInfo failed");
//			}
//		}
//		
//		return dependiencesMap;
//	}

//	public static SceneBundleInfo getSceneBundleInfo(this AssetBundle bundle, string levelName)
//	{
//		SceneBundleInfo prepareBundleNames = null;
////		TextAsset sceneConfig = bundle.Load(levelName + BundleManager.sceneBundleDependenceSuffix, typeof(TextAsset)) as TextAsset;
//		TextAsset sceneConfig = null;
//		Object[] s = BundleManager.LoadAll(bundle);
//		if(s.Length > 0)
//		{
//			sceneConfig = s[0] as TextAsset;
//		}
//
//		if(sceneConfig != null)
//		{
//			try
//			{
//				prepareBundleNames = SceneBundleInfo.CreateByBytes(sceneConfig.bytes);
//			}
//			catch(System.Exception e)
//			{
//				Debug.LogException(e);
//				Debug.LogError("BundleManager: DeserializeObject failed");
//			}
//		}
//
//		return prepareBundleNames;
//	}
}